#include "FileCat.h"

using namespace std;

CFileCat::CFileCat(void) : m_hFileOut(NULL)
{
}

CFileCat::~CFileCat(void)
{
}

void CFileCat::InitCmdSet()
{
	if (m_vecValidCmd.empty())
	{
		ResponseFun pFunOfile = (CFileCat::ResponseFun)ProcessOpenOfile;
		ResponseFun pFunIfileS = (CFileCat::ResponseFun)ProcessIfileS;
		ResponseFun pFunIfileA = (CFileCat::ResponseFun)ProcessIfileA;
		ResponseFun pFunOffset = (CFileCat::ResponseFun)ProcessOffset;

		//this seq is process seq
		m_vecValidCmd.push_back(pair<CStringA, ResponseFun>("ofile", pFunOfile));
		m_vecValidCmd.push_back(pair<CStringA, ResponseFun>("ifiles", pFunIfileS));
		m_vecValidCmd.push_back(pair<CStringA, ResponseFun>("offset", pFunOffset));
		m_vecValidCmd.push_back(pair<CStringA, ResponseFun>("ifilea", pFunIfileA));
	}
}

bool CFileCat::CheckCmdValid( const CStringA& strCmd )
{
	bool bRet = false;
	vector<pair<CStringA, ResponseFun>>::iterator it = m_vecValidCmd.begin();
	for (; it != m_vecValidCmd.end(); it++)
	{
		if (0 == it->first.CompareNoCase(strCmd))
		{
			bRet = true;
			break;
		}
	}

	return bRet;
}

bool CFileCat::AddCmd( const CStringA& strCmd, const CStringA& strValue )
{
	if (CheckCmdValid(strCmd))
	{
		m_mapUserCmd.insert(make_pair<CStringA, CStringA>(strCmd, strValue));
		return true;
	}
	else
	{
		return false;
	}
	
}

bool CFileCat::DoProcess()
{
	vector<pair<CStringA, ResponseFun>>::iterator itCmd = m_vecValidCmd.begin();
	bool bResult = false;
	for (; itCmd != m_vecValidCmd.end(); itCmd++)
	{
		map<CStringA, CStringA>::iterator itUercmd = m_mapUserCmd.find(itCmd->first);
		if (itUercmd != m_mapUserCmd.end())
		{
			bResult = itCmd->second(this, itUercmd->second);
			if (!bResult)
			{
				return false;
			}
		}
	}

	return true;
}

bool CFileCat::DoProcessEnd()
{
	m_vecValidCmd.clear();
	BOOL bClose = CloseHandle(m_hFileOut);
	m_hFileOut = NULL;

	if (!bClose)
	{
		return false;
	}
	return true;
}
//////////////////////////////////////////////////////////////////////////
//
//
bool CFileCat::ProcessOpenOfile( void* pArg, const CStringA& strOutFilePath)
{
	CFileCat* pFileCat = (CFileCat*)(pArg);
	if (pFileCat)
	{
		pFileCat->m_hFileOut = CreateFileA(strOutFilePath, GENERIC_READ | GENERIC_WRITE,
			FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
		if (INVALID_HANDLE_VALUE == pFileCat->m_hFileOut)
		{
			return false;
		}
		return true;
	}
	return false;
}

bool CFileCat::ProcessIfileS( void* pArg, const CStringA& strSourceFilePath)
{
	bool bRet = true;
	do 
	{
		CFileCat* pFileCat = (CFileCat*) pArg;
		if (!pFileCat)
		{
			bRet = false;
			break;
		}

		HANDLE hSourceFile = CreateFileA(strSourceFilePath, GENERIC_READ, 
			FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
		if (INVALID_HANDLE_VALUE == hSourceFile)
		{
			bRet = false;
			break;
		}

		bRet = CFileCat::CopyFile(pFileCat->m_hFileOut, hSourceFile);

		CloseHandle(hSourceFile);
		hSourceFile = NULL;
	} while (FALSE);
	return bRet;
}

bool CFileCat::ProcessIfileA( void* pArg, const CStringA& strAddionFilePath)
{
	bool bRet = true;
	do 
	{
		CFileCat* pFileCat = (CFileCat*) pArg;
		if (!pFileCat)
		{
			bRet = false;
			break;
		}

		HANDLE hSourceFile = CreateFileA(strAddionFilePath, GENERIC_READ, 
			FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
		if (INVALID_HANDLE_VALUE == hSourceFile)
		{
			bRet = false;
			break;
		}

		bRet = CFileCat::CopyFile(pFileCat->m_hFileOut, hSourceFile);

		CloseHandle(hSourceFile);
		hSourceFile = NULL;
	} while (FALSE);
	return bRet;
}

bool CFileCat::ProcessOffset( void* pArg, const CStringA& strOffset)
{
	bool bRet = false;
	do 
	{
		CFileCat* pFileCat = (CFileCat*)pArg;
		if (!pFileCat)
		{
			break;
		}

		const DWORD dwFilePointer = atoi(strOffset);
		DWORD dwFilePinterPose = ::SetFilePointer(pFileCat->m_hFileOut,
			dwFilePointer, NULL, FILE_BEGIN);
		if (dwFilePinterPose == dwFilePointer)
		{
			bRet = true;
		}
	} while (FALSE);
	return bRet;
}

//////////////////////////////////////////////////////////////////////////
bool CFileCat::CopyFile( HANDLE hDestFile, HANDLE hSourceFile )
{
	bool bRet = true;
	if (!hDestFile || INVALID_HANDLE_VALUE == hDestFile
		|| !hSourceFile || INVALID_HANDLE_VALUE == hSourceFile)
	{
		return false;
	}


	//copy file
#define PAGE_SIZE (4 * 1024)
	unsigned char strTmpData[PAGE_SIZE] = {};
	DWORD dwFileSize = GetFileSize(hSourceFile, NULL);
	DWORD dwRemain = dwFileSize;
	//
	do 
	{
		SecureZeroMemory(strTmpData, sizeof(strTmpData));
		DWORD dwCurrentSize = PAGE_SIZE > dwRemain ? dwRemain : PAGE_SIZE;
		DWORD dwOperateSize = 0;
		BOOL bRead = ReadFile(hSourceFile, strTmpData, dwCurrentSize, &dwOperateSize, NULL);

		if (bRead && dwCurrentSize == dwOperateSize)
		{
			dwRemain -= dwCurrentSize;
			BOOL bWrite = WriteFile(hDestFile, strTmpData,
				dwCurrentSize, &dwOperateSize, NULL);
			if (!bWrite || dwOperateSize != dwCurrentSize)
			{
				bRet = false;
				break;
			}
		}
		else
		{
			bRet = false;
			break;
		}
	} while (dwRemain > 0);

	return bRet;
}
